package com.spring;

import com.zhouyu.AppConfig;
import com.zhouyu.service.ZhouyuBeanPostProcessor;

import java.beans.Introspector;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.*;

public class ZhouyuApplicationConext {

	private Class appConfigClass;
	private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();
	//单例池
	private Map<String,Object> singletonObjects = new HashMap<>();

	private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

	public ZhouyuApplicationConext(Class appConfigClass) {
		this.appConfigClass = appConfigClass;

		//扫描
		scan(appConfigClass);

		//创建单例bean
		for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
			String beanName = entry.getKey();
			BeanDefinition beanDefinition = entry.getValue();

			if (beanDefinition.getScope().equals("singleton")){
				Object bean = createBean(beanName, beanDefinition);
				singletonObjects.put(beanName,bean);

			}
		}
	}

	private Object createBean(String beanName,BeanDefinition beanDefinition){
		Class clazz = beanDefinition.getType();
		Object instance = null;
		try {
			instance = clazz.getConstructor().newInstance();

			for (Field field : clazz.getDeclaredFields()) {
				if (field.isAnnotationPresent(Autowired.class)){
					field.setAccessible(true);
//					Class<?> type = field.getType();
					//当前实现为根据name获取beam
					field.set(instance,getBean(field.getName()));
				}
			}

			if (instance instanceof BeanNameAware) {
				((BeanNameAware)instance).setBeanName(beanName);
			}

			for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
				instance = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
			}

			if (instance instanceof InitializingBean){
				((InitializingBean)instance).afterPropertiesSet();
			}

			for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
				instance = beanPostProcessor.postProcessAfterInitialization(instance,beanName);
			}

		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		return instance;
	}

	private void scan(Class appConfigClass) {
		if(appConfigClass.isAnnotationPresent(ComponentScan.class)){
			ComponentScan componentScanAnnotation = (ComponentScan) appConfigClass.getAnnotation(ComponentScan.class);

			String path = componentScanAnnotation.value();

			path = path.replace(".","/");
			ClassLoader classLoader = ZhouyuApplicationConext.class.getClassLoader();
			URL resource = classLoader.getResource(path);

			File file = new File(resource.getFile());

			if (file.isDirectory()){
				for (File f : file.listFiles()){
					String absolutePath = f.getAbsolutePath();

					absolutePath = absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
					absolutePath = absolutePath.replace("\\",".");

					try {
						Class<?> clazz = classLoader.loadClass(absolutePath);

						if (clazz.isAnnotationPresent(Component.class)){

							//判断是否实现接口
							if(BeanPostProcessor.class.isAssignableFrom(clazz)){
								BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
								beanPostProcessorList.add(instance);
							}

							Component componentAnnotation = clazz.getAnnotation(Component.class);
							String beanName = componentAnnotation.value();

							if ("".equals(beanName)){
//								beanName = clazz.getSimpleName();
//								beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
								//Spring方式
								beanName = Introspector.decapitalize(clazz.getSimpleName());
							}

							BeanDefinition beanDefinition = new BeanDefinition();
							beanDefinition.setType(clazz);


							if (clazz.isAnnotationPresent(Scope.class)) {
								Scope scope = clazz.getAnnotation(Scope.class);
								String value = scope.value();
								beanDefinition.setScope(value);
							}else {
								//单例
								beanDefinition.setScope("singleton");
							}

							beanDefinitionMap.put(beanName,beanDefinition);
						}
					} catch (ClassNotFoundException | NoSuchMethodException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					} catch (InstantiationException e) {
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					}


				}
			}
		}
	}

	public Object getBean(String beanName) {
		if (!beanDefinitionMap.containsKey(beanName)){
			throw  new NullPointerException();
		}

		BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

		if (beanDefinition.getScope().equals("singleton")){
			//单例
			Object singletonBean = singletonObjects.get(beanName);

			if (Objects.isNull(singletonBean)){
				singletonBean = createBean(beanName,beanDefinition);
				singletonObjects.put(beanName,singletonBean);
			}

			return singletonBean;
		}else {
			//原型
			Object prototypeBean = createBean(beanName, beanDefinition);
			return prototypeBean;
		}
	}
}
